package com.jd.basic.service.impl;

import com.jd.basic.constant.PhoneRegisterCons;
import com.jd.basic.constant.WechatLoginCons;
import com.jd.basic.dto.RegisterDto;
import com.jd.basic.dto.RegisterEmailDto;
import com.jd.basic.dto.VerifyEmailDto;
import com.jd.basic.service.VerifyCodeService;
import com.jd.basic.utils.BusinessException;
import com.jd.basic.utils.MailUtils;
import com.jd.basic.utils.StrUtils;
import com.jd.basic.utils.VerifyCodeUtils;
import com.jd.basic.dto.VerifyDto;
import com.jd.user.domain.Logininfo;
import com.jd.user.domain.User;
import com.jd.user.mapper.LogininfoMapper;
import com.jd.user.mapper.UserMapper;
import com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO;
import lombok.Builder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisKeyExpiredEvent;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * @author 小林同学
 * @version 1.0
 * @description: TODO
 * @date 2023/3/3 22:56
 */
@Service
@Slf4j
@Builder
public class VerifyCodeServiceImpl implements VerifyCodeService {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Override
    public String getCode(String imageCodeKey) throws IOException {
        // 随机生成4位数
        String code = StrUtils.getComplexRandomString(4);

        log.info("图形验证码{}",code);
        // 将随机生成的数存到redis里面，有效期3分钟
        redisTemplate.opsForValue().set(imageCodeKey,code,3, TimeUnit.MINUTES);
        // 使用工具类将随机数进行base64编码
        String verifyCode= VerifyCodeUtils.VerifyCode(60, 30, code);

        return verifyCode;
    }

    @Override
    public void smsCode(VerifyDto verifyDto) {
        if ("binder".equals(verifyDto.getType())){
            this.SendRedisCode(verifyDto, WechatLoginCons.WECHAT_CODE_KEY);
        } else if ("register".equals(verifyDto.getType())) {
            this.checkImageCode(verifyDto);
            this.SendRedisCode(verifyDto, PhoneRegisterCons.PHONE_CODE_KEY);
        }
//        // 发送短信
//        SmsUtil.send();
    }

    private void checkImageCode(VerifyDto verifyDto) {
        // 校验参数 （dto已做）
        // 判断图形验证码是否正确
        String imageCodeRedis = (String) redisTemplate.opsForValue().get(verifyDto.getImageCodeKey());
        if (null == imageCodeRedis || !imageCodeRedis.equals(verifyDto.getImageCodeValue())){
            throw new BusinessException("图形验证码错误");
        }
        // 判断手机号是否已注册
        User user = userMapper.findByPhone(verifyDto.getPhone());
        if (null != user ) {
            throw new BusinessException("已注册，请登录");
        }
    }

    private void SendRedisCode(VerifyDto verifyDto, String rediskey) {
        // 用户点击获取，后端获取验证码，存入redis中
        // 先判断是否重复发送验证码，即还没到60s，就再次发送验证码
        Long timeOut = redisTemplate.getExpire(String.format(rediskey, verifyDto.getPhone()));
        if (timeOut > (PhoneRegisterCons.PHONE_CODE_TIME - 60)){
            throw new BusinessException("重复获取验证码");
        }
        // 判断是否需要生成新的验证码,需要去redis里面去找
        String phoneCodeRedis = (String) redisTemplate.opsForValue().get(String.format(rediskey, verifyDto.getPhone()));
        // 如果redis没有验证码，就生成一个,
        if(null == phoneCodeRedis){
             phoneCodeRedis = StrUtils.getRandomString(4);

        }
        log.info("验证码:{}",phoneCodeRedis);
        // 将生成的验证码存入redis中
        redisTemplate.opsForValue().set(String.format(rediskey, verifyDto.getPhone()),phoneCodeRedis, 5,TimeUnit.MINUTES);
    }

    @Override
    public void phoneRegister(RegisterDto registerDto) {
        // 参数校验
        // 判断手机号是否已注册
        User user = userMapper.findByPhone(registerDto.getPhone());
        if (null != user ) {
            throw new BusinessException("已注册，请登录");
        }
        // 校验手机验证码是否和redis的一致
        String phoneCodeRedis = (String) redisTemplate.opsForValue().get(String.format(PhoneRegisterCons.PHONE_CODE_KEY, registerDto.getPhone()));


        if (null == phoneCodeRedis || ! phoneCodeRedis.equals(registerDto.getSmsCode())) {
            throw new BusinessException("手机验证码错误");
        }
        // 校验 密码和确认密码是否一至
        if (! registerDto.getPassword().equals(registerDto.getPasswordConfirm())){
            throw new BusinessException("两次密码不一致");

        }
        // 完成注册，将用户信息传入user表和logininfo表
        // 先传入logininfo
        // 将提交数据封装成一个参数
        Logininfo logininfo = new Logininfo();
        logininfo = registerDto.getLogininfo();
        // 添加提交信息到logininfo表中
        logininfoMapper.add(logininfo);
        // 获取logininfo表里刚才提交信息那一条的id
        Long logininfoId = logininfo.getId();
        // 传入user表
        User user1 = new User();
        user1 = registerDto.getUser();
        user1.setLogininfoId(logininfoId);
        userMapper.add(user1);
    }

    @Override
    public void emailRegister(RegisterEmailDto registerEmailDto) {
        // 参数校验
        // 判断手机号是否已注册
        User user = userMapper.findByEmail();
        if (null != user){
            throw new BusinessException("已注册，请登录");
        }
        // 校验 密码和确认密码是否一至
        if (! registerEmailDto.getPassword().equals(registerEmailDto.getPasswordConfirm())){
            throw new BusinessException("两次密码不一致");
        }

        // 完成注册，将用户信息传入user表和logininfo表
        // 先传入logininfo
        // 将提交数据封装成一个参数
        Logininfo logininfo = new Logininfo();
        logininfo = registerEmailDto.getLogininfo();
        // 添加提交信息到logininfo表中
        logininfoMapper.add(logininfo);
        // 获取logininfo表里刚才提交信息那一条的id
        Long logininfoId = logininfo.getId();
        // 传入user表
        User user1 = new User();
        user1 = registerEmailDto.getUser();
        user1.setLogininfoId(logininfoId);
        userMapper.add(user1);
    }

    @Override
    public void sendEmailSmsCode(VerifyEmailDto dto) {
        // 校验参数 （dto已做）
        // 判断图形验证码是否正确
        String imageCodeRedis = (String) redisTemplate.opsForValue().get(dto.getImageCodeKey());
        if (null == imageCodeRedis || !imageCodeRedis.equals(dto.getImageCodeValue())){
            throw new BusinessException("图形验证码错误");
        }
        // 判断邮箱号是否已注册
        User user = userMapper.findByEmail();
        if (null != user){
            throw new BusinessException("已注册，请登录");
        }
        // 用户点击获取，后端获取验证码，存入redis中
        // 先判断是否重复发送验证码，即还没到60s，就再次发送验证码
        Long timeOut = redisTemplate.getExpire(String.format(PhoneRegisterCons.PHONE_CODE_KEY, dto.getEmail()));
        if (timeOut > (PhoneRegisterCons.PHONE_CODE_TIME - 60)){
            throw new BusinessException("重复获取验证码");
        }
        // 判断是否需要生成新的验证码,需要去redis里面去找
        String emailCodeRedis = (String) redisTemplate.opsForValue().get(String.format(PhoneRegisterCons.PHONE_CODE_KEY, dto.getEmail()));
        // 如果redis没有验证码，就生成一个,
        if(null == emailCodeRedis){
            emailCodeRedis = StrUtils.getRandomString(4);

        }
        log.info("验证码:{}",emailCodeRedis);
        // 将生成的验证码存入redis中
        redisTemplate.opsForValue().set(String.format(PhoneRegisterCons.PHONE_CODE_KEY, dto.getEmail()),emailCodeRedis, 5,TimeUnit.MINUTES);

        // 发送邮件
        MailUtils.sendMail(dto.getEmail(),"验证码为：" + emailCodeRedis,"邮箱注册验证码");

    }

}
